from urllib.parse import urljoin
import logging
import requests
import json

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


class MCPClient:
    def __init__(self, server_url):
        self.protocol_version = "2025-06-18"
        self.client_info = {"name": "MCP客户端", "version": "1.0.0"}
        # 服务器的信息 现在还没连接上服务器
        self.server_info = None
        # 服务器提供的能力
        self.capabilities = None
        # 初始化消息ID，默认为1
        self.message_id = 1
        self.server_url = server_url.rstrip("/")  # http://localhost:8000
        self.mcp_endpoint = urljoin(
            self.server_url, "/mcp"
        )  # http://localhost:8000/mcp
        # 创建requests的session对象 requests就类似于node里面的axios
        self.session = requests.Session()
        # 告诉 服务器我只接收json和event-stream
        self.session.headers.update(
            {
                "Accept": "application/json,text/event-stream",
                "MCP-Protocol-Version": self.protocol_version,
            }
        )
        self.session_id = None

    def open_sse_stream(self):
        try:
            headers = {"Accept": "text/event-stream"}
            if self.session_id:
                headers["Mcp-Session-Id"] = self.session_id
            response = self.session.get(
                self.mcp_endpoint, headers=headers, stream=True, timeout=60
            )
            if response.status_code == 200:
                logger.info("SSE流打开成功")
                return response
            else:
                logger.info("SEE流打开失败")
                return None
        except requests.exceptions.RequestException as e:
            logger.error(f"SEE流打开失败:{str(e)}")
            return None

    def call_tool(self, tool_name, arguments):
        request = {
            "jsonrpc": "2.0",
            "id": self._generated_id(),
            "method": "tools/call",
            "params": {"calls": [{"name": tool_name, "arguments": arguments}]},
        }
        response = self._send_message(request)
        print("call_tool", response)
        if response and "result" in response:
            calls = response["result"].get("calls", [])
            if calls:
                return calls[0]
        else:
            logger.error(f"调用工具失败")
        return None

    def list_tools(self):
        request = {
            "jsonrpc": "2.0",
            "id": self._generated_id(),
            "method": "tools/list",
            "params": {},
        }
        response = self._send_message(request)
        if response and "result" in response:
            tools = response["result"].get("tools", [])
            return tools
        else:
            return []

    def get_session_info(self):
        return {
            "session_id": self.session_id,
            "server_url": self.server_url,
            "protocol_version": self.protocol_version,
        }

    def _generated_id(self):
        self.message_id += 1
        return str(self.message_id)

    def initialize(self):
        # 构建初始化的请求
        request = {
            "jsonrpc": "2.0",
            "id": self._generated_id(),
            "method": "initialize",
            "params": {
                "protocolVersion": self.protocol_version,
                "capabilities": {},
                "clientInfo": self.client_info,
            },
        }
        response = self._send_message(request)
        if response and "result" in response:
            result = response["result"]
            self.server_info = result.get("server_info")
            self.capabilities = result.get("capabilities")
            if "session_id" in result:
                self.session_id = result["session_id"]
            logger.info(f"服务器已经初始化成功,session_id={self.session_id}")
            return True
        else:
            logger.info("服务器已经初始化失败")
            return False

    def _send_message(self, message):
        try:
            # 初始化请求头字典
            headers = {}
            if self.session_id:
                headers["Mcp-Session-Id"] = self.session_id
            # 发送POST请求到MCP的端口
            response = self.session.post(
                self.mcp_endpoint, json=message, headers=headers, timeout=30
            )
            if response.status_code == 200:
                new_session_id = response.headers.get("Mcp-Session-Id")
                if new_session_id and new_session_id != self.session_id:
                    self.session_id = new_session_id
                return response.json()
            elif response.status_code == 202:
                return None
            elif response.status_code == 400:
                return None
            elif response.status_code == 401:
                return None
            elif response.status_code == 404:
                self.session_id = None
                return None
            else:
                logger.error(f"HTTP请求错误:{response.status_code}- {response.text}")
                return None
        except Exception as e:
            logger.error(f"HTTP请求错误:{str(e)}")
            return None


def http_transport():
    mcpClient = MCPClient("http://localhost:8000")
    try:
        # 1.初始化客户端与服务器的连接
        if not mcpClient.initialize():
            print("初始化失败")
            return
        ## 2.获取会话信息
        # session_info = mcpClient.get_session_info()
        # print(f"会话信息:{session_info}")
        ## 3.获取工具列表
        # tools = mcpClient.list_tools()
        # print(f"可用工具:{[tool["name"] for tool in tools]}")
        ## 4.调用工具
        # result = mcpClient.call_tool("calculate", {"expression": "10/2+5"})
        # if result:
        #    contents = result.get("contents", [])
        #    if contents:
        #        print(f"计算结果:{contents[0].get('text','')}")
        sse_response = mcpClient.open_sse_stream()
        if sse_response:
            print(f"SSE流式传输创建成功")
            try:
                # 持续监听服务器发过来的SSE消息 chunk_size=1就是不使用缓存
                for line in sse_response.iter_lines(chunk_size=1, decode_unicode=True):
                    if line.startswith("event: "):  # event: connection
                        event_type = line[7:]
                    elif line.startswith("data: "):
                        data_str = line[6:]
                        try:
                            data = json.loads(data_str)
                            if event_type == "connected":
                                status = data.get("status")
                                session_id = data.get("session_id")
                                print(f"连接状态:{status},会话ID:{session_id}")
                            elif event_type == "time_update":
                                server_time = data.get("server_time")
                                session_id = data.get("session_id")
                                print(
                                    f"服务器最新时间:{server_time},会话ID:{session_id}"
                                )
                            else:
                                print(f"未知事件类型:{event_type},data:{data}")
                        except json.JSONDecodeError:
                            print(f"JSON数据解析失败:{data_str}")
                    elif line == "":
                        continue
            except KeyboardInterrupt:
                print(f"用户停止监听")
            finally:
                sse_response.close()
                print(f"SSE流式已经关闭")

    except Exception as e:
        print(f"HTTP通信错误:{str(e)}")


def main():
    http_transport()


if __name__ == "__main__":
    main()
